﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using BattleCore;
using BattleCore.Events;
using PsyModules;

namespace Battle
{
    public class BattleControl
    {
        // Custom chat module
        private ShortChat msg = new ShortChat();

        // List of battle players
        private List<BattlePlayer> _BattlePlayers = new List<BattlePlayer>();

        // Battle Boxes and settings
        private List<BattleBox> _BattleBoxes = new List<BattleBox>();
        public List<BattleBox> Boxes
        {
            get { return _BattleBoxes; }
            set { _BattleBoxes = value; }
        }
        // Default settings in case we reset
        private List<BattleBox> _BattleBoxesDefault = new List<BattleBox>();
        public List<BattleBox> BoxesDefault
        {
            get { return _BattleBoxesDefault; }
            set { _BattleBoxesDefault = value; }
        }

        // Put box numbers in here
        private List<int> BoxDelays = new List<int>();

        // ------------------------------\\
        //  Battle Timer                  |
        // ------------------------------//
        public void TimerBattleControl(Queue<EventArgs> q)
        {
            // Checking if any games are about to start
            int num = 0;
            bool found = false;
            // checking list
            BoxDelays.ForEach(delegate(int i)
            {
                // checking if time expired
                if ((_BattleBoxes[i].GameDelay - DateTime.Now).Duration() > TimeSpan.FromSeconds(5))
                {
                    q.Enqueue(msg.arena("Starting Box [ " + i + " ] - Box removed from BoxDelays list."));
                    num = i;
                    found = true;
                    // Full energy in case winner is low
                    _BattleBoxes[i].SendBoxMessage("*prize #13", q);
                    // Give weapons back
                    _BattleBoxes[i].SendBoxMessage("*prize 99", q);
                }
            });

            // remove the timer if it expired
            if (found)
                BoxDelays.Remove(num);
        }

        // Handles all events for battle boxes
        public void BattleEventHandler(StatusControl stat,StatusControl.MainPlayer p_Status, EventArgs e, Queue<EventArgs> q)
        {
            BattlePlayer Bplayer = new BattlePlayer();

            if (e is ShipChangeEvent)
            {
                ShipChangeEvent s = (e as ShipChangeEvent);
                Bplayer = _BattlePlayers.Find(item => item.PlayerName == s.PlayerName);
                if (Bplayer != null)
                {
                    // Player changed ships before game starts, resets game start
                    if (!_BattleBoxes[Bplayer.BoxNum].GameOn && BoxDelays.Contains(Bplayer.BoxNum))
                    {
                        Bplayer.SC_Stamp = DateTime.Now;
                        _BattleBoxes[Bplayer.BoxNum].GameDelay = DateTime.Now;
                    }
                    // If player changes ship during match
                    else if (_BattleBoxes[Bplayer.BoxNum].GameOn)
                    {
                        if ((Bplayer.SC_Stamp - DateTime.Now).Duration() > TimeSpan.FromSeconds(5))
                        {

                        }
                        else
                        {
                            // resetting ship change time stamp
                            Bplayer.SC_Stamp = DateTime.Now;
                        }
                    }
                }
                q.Enqueue(msg.arena("Error: b_player is = null."));
            }
            else if (e is PlayerDeathEvent)
            {
                PlayerDeathEvent p = e as PlayerDeathEvent;
                Bplayer = _BattlePlayers.Find(item => item.PlayerName == p.KilledName);
                BattleBox box = _BattleBoxes[Bplayer.BoxNum];

                // PUT Code to deduct
                if (box.BoxGame == GameType.Duel)
                {
                    if (box.WaitQ.Count > 0)
                    {
                        // configure battle player info
                        BattlePlayer player2add = _BattlePlayers.Find(item => item.PlayerName == box.WaitQ[0]);
                        player2add.Freq = Bplayer.Freq;
                        player2add.BoxNum = Bplayer.BoxNum;
                        player2add.TeamNum = Bplayer.TeamNum;
                        player2add.Waitting = false;

                        // configure box info to match
                        _BattleBoxes[player2add.BoxNum].Teams[player2add.TeamNum].TeamOwner = player2add.PlayerName;
                        _BattleBoxes[player2add.BoxNum].Teams[player2add.TeamNum].TeamSlots[0].ActivePlayer = player2add;
                        
                        // remove loser from battle list - he is now going to be  InSpec
                        _BattlePlayers.Remove(Bplayer);
                        // Put loser into spec
                        q.Enqueue(msg.pm(p.KilledName,"*spec"));
                        q.Enqueue(msg.pm(p.KilledName, "*spec"));
                        // set his status to InSpec
                        stat.GetPlayer(p.KilledName).PlayerStatus = Status.InSpec;

                        stat.GetPlayer(box.WaitQ[0]).PlayerStatus = Status.InBattle;
                        // Put next in line in ship
                        q.Enqueue(msg.pm(player2add.PlayerName, "*setship 1"));
                        // remove him from box wait list
                        box.WaitQ.Remove(box.WaitQ[0]);

                        // gameover
                        box.GameOver(q);
                        // set game start delay
                        BoxDelays.Add(Bplayer.BoxNum);
                    }
                    else
                    {
                        box.GameOver(q);
                        // resetting ship change time stamp
                        Bplayer.SC_Stamp = DateTime.Now;
                        BoxDelays.Add(Bplayer.BoxNum);
                    }
                }
            }
        }

        public Queue<EventArgs> BattleChatCommands(ChatEvent c, Battle.StatusControl.MainPlayer player)
        {
            Queue<EventArgs> reply = new Queue<EventArgs>();

            if (c.Message.StartsWith("!boxes"))
            {
                _BattleBoxes.ForEach(delegate(BattleBox b)
                {
                    reply.Enqueue(msg.arena("--------------------<[ Box " + (_BattleBoxes.IndexOf(b) + 1) + " ]--------------------[> - <]"));
                    reply.Enqueue(msg.arena(("[ " + "BoxName ]:   ".PadLeft(15, ' ') + b.BoxName + " ").PadRight(50, ' ') + "[> - <]"));
                    reply.Enqueue(msg.arena(("[ " + "GameType ]:   ".PadLeft(15, ' ') + b.BoxGame + " ").PadRight(50, ' ') + "[> B <]"));
                    reply.Enqueue(msg.arena(("[ " + "Lives ]:   ".PadLeft(15, ' ') + b.Lives + " ").PadRight(50, ' ') + "[> A <]"));
                    reply.Enqueue(msg.arena(("[ " + "Locked ]:   ".PadLeft(15, ' ') + b.Locked + " ").PadRight(50, ' ') + "[> T <]"));
                    reply.Enqueue(msg.arena(("[ " + "NumTeams ]:   ".PadLeft(15, ' ') + b.NumTeams + " ").PadRight(50, ' ') + "[> T <]"));
                    reply.Enqueue(msg.arena(("[ " + "TeamSize ]:   ".PadLeft(15, ' ') + b.TeamSize + " ").PadRight(50, ' ') + "[> L <]"));
                    reply.Enqueue(msg.arena(("[ " + "Location ]:   ".PadLeft(15, ' ') + "(X:" + b.Location[0] + "|Y:" + b.Location[1] + ")  (X:" + b.Location[2] + "|Y:" + b.Location[3] + ")").PadRight(50, ' ') + "[> E <]"));
                    reply.Enqueue(msg.arena(("[ " + "Game On ]:   ".PadLeft(15, ' ') + b.GameOn + " ").PadRight(50, ' ') + "[> - <]"));
                    reply.Enqueue(msg.arena(("[ " + "Game Type ]:   ".PadLeft(15, ' ') + b.BoxGame.ToString() + " ").PadRight(50, ' ') + "[> - <]"));
                    //reply.Enqueue(msg.pm(c.PlayerName, ("Debug: NumTeams=" + b.Teams.Count)));
                    //reply.Enqueue(msg.pm(c.PlayerName, ("Debug: TeamSize=" + b.Teams[0].TeamSlots.Count)));
                });
            }
            else if (c.Message.StartsWith("!next"))
                DoNext(c,reply,player);
            else if (c.Message.StartsWith("!box"))
            {
                int num;
                bool isnum = int.TryParse(c.Message.Split(' ')[1], out num);
                
                if (isnum && num <= _BattleBoxes.Count && num > 0)
                {
                    BattleBox b = _BattleBoxes[num - 1];
                    reply.Enqueue(msg.arena("-----------<[ Box " + num + "'s Info ]>-----------<"));
                    reply.Enqueue(msg.arena("BoxName = ".PadLeft(12, ' ') + "[ " + check(b.BoxName) + " ]"));
                    reply.Enqueue(msg.arena("GameType = ".PadLeft(12, ' ') + "[ " + check(b.BoxGame.ToString()) + " ]"));
                    reply.Enqueue(msg.arena("BoxOwner = ".PadLeft(12, ' ') + "[ " + check(b.BoxOwner) + " ]"));
                    for (int i = 0; i < b.Teams.Count; i++)
                    {
                        reply.Enqueue(msg.arena("--------------<[ Team :" + b.Teams[i].TeamName + " ]"));
                        reply.Enqueue(msg.arena(" Freq: [ " + check(b.Teams[i].Freq.ToString()) + " ]"));
                        reply.Enqueue(msg.arena("Owner: [ " + check(b.Teams[i].TeamOwner) + " ]"));
                        for (int j = 0; j < b.Teams[i].TeamSlots.Count; j++)
                        {
                            reply.Enqueue(msg.arena("-------------<[ Member " + j + " ]"));
                            reply.Enqueue(msg.arena(" Name: " + check(b.Teams[i].TeamSlots[j].ActivePlayer.PlayerName)));
                            reply.Enqueue(msg.arena("Lives: " + check(b.Teams[i].TeamSlots[j].Lives.ToString())));
                            reply.Enqueue(msg.arena("Ready: " + check(b.Teams[i].TeamSlots[j].Ready.ToString())));
                        }
                    }
                }
                else
                    reply.Enqueue(msg.arena(("Try using the right syntax. !box [box number]")));
            }

            return reply;
        }
        private string check(string format)
        {
            if (format != null)
                return format;
            else
                return "~ not registered yet";
        }
        public void DoNext(ChatEvent c, Queue<EventArgs> q, Battle.StatusControl.MainPlayer s_player)
        {
            // Player is on the battle main list
            if (_BattlePlayers.Exists(delegate(BattlePlayer p) { return p.PlayerName == s_player.PlayerName; }))
            {
                BattlePlayer b_player = _BattlePlayers.Find(item => item.PlayerName == s_player.PlayerName);

                // player is waitting for another box
                if (b_player.Waitting)
                {
                    q.Enqueue(msg.pm(c.PlayerName, "You are currently in line for Box[ "+ (b_player.BoxNum + 1) + " ]. To leave the line type !cancel."));

                    string wait_list = "Wait List for Box[ " + (b_player.BoxNum + 1) + " ]: ";
                    for (int i = 0; i < _BattleBoxes[b_player.BoxNum].WaitQ.Count; i++)
                    {
                        wait_list += " [" + (i+1) + "]" + _BattleBoxes[b_player.BoxNum].WaitQ[i] + ",";
                    }

                    q.Enqueue(msg.pm(c.PlayerName, wait_list));
                }
            }
            else
            {
                if (c.Message.Length == 5)
                    q.Enqueue(msg.pm(c.PlayerName, "Please choose a number between 1 and " + _BattleBoxes.Count + "."));
                else if (!c.Message.Contains(" "))
                    q.Enqueue(msg.pm(c.PlayerName, "Please type !next [box number]. EXAMPLE: !next 1"));
                else
                {
                    int num;
                    bool isnum = int.TryParse(c.Message.Split(' ')[1], out num);

                    if (isnum)
                    {
                        if (num <= _BattleBoxes.Count && num > 0)
                            CheckBoxStatus(num, q, s_player);
                        else
                            q.Enqueue(msg.pm(c.PlayerName, "Im sorry! Your selection is outside the box range. Please choose a number between 1 and " + _BattleBoxes.Count + "."));
                    }
                    else
                        q.Enqueue(msg.pm(c.PlayerName, "I'm sorry i do not understand [ " + c.Message.Split(' ')[1] + " ]. Please type !next[box number]. EXAMPLE: !next 1"));
                }
            }
        }
        private void CheckBoxStatus(int num, Queue<EventArgs> q, Battle.StatusControl.MainPlayer player)
        {
            if (_BattleBoxes[num - 1].Locked)
                q.Enqueue(msg.pm(player.PlayerName, "I'm sorry, this box is currently locked. If you think an error has been made, please ask a Battle Admin for assistance."));
            else if (_BattleBoxes[num - 1].GameOn)
                q.Enqueue(msg.pm(player.PlayerName, "I'm sorry, there is currently a game in progress. Please choose another box."));
            else //if (_BattleBoxes[num - 1].BoxGame == GameType.Normal)
            {
                if (_BattleBoxes[num - 1].AvailableTeamOwner != null)
                {
                    int teamnum = (int)_BattleBoxes[num - 1].AvailableTeamOwner;
                    // change player main status
                    player.PlayerStatus = Status.InBattle;
                    // configure and include inside battlecontrol list
                    BattlePlayer newP = new BattlePlayer();
                    newP.PlayerName = player.PlayerName;
                    newP.Freq = _BattleBoxes[num - 1].Teams[teamnum].Freq;
                    newP.BoxNum = num - 1;
                    newP.TeamNum = teamnum;

                    _BattleBoxes[num - 1].Teams[teamnum].TeamOwner = newP.PlayerName;
                    _BattleBoxes[num - 1].Teams[teamnum].TeamSlots[0].ActivePlayer = newP;

                    _BattlePlayers.Add(newP);

                    _BattleBoxes[num - 1].UpdateBox(q, BoxDelays);

                    q.Enqueue(msg.pm(player.PlayerName, "*setship 1"));
                    //q.Enqueue(msg.pm(player.PlayerName, "Place player inside team[" + _BattleBoxes[num - 1].AvailableTeamOwner + "]"));
                }
                else
                {
                    // configure and include inside battlecontrol list
                    BattlePlayer newP = new BattlePlayer();
                    newP.PlayerName = player.PlayerName;
                    newP.BoxNum = num - 1;
                    newP.Waitting = true;
                    _BattlePlayers.Add(newP);

                    _BattleBoxes[num - 1].WaitQ.Add(player.PlayerName);

                    q.Enqueue(msg.pm(player.PlayerName, "You have been added to Box[" + num + "] wait list."));

                    string wait_list = "Wait List for Box[ " + (newP.BoxNum + 1) + " ]: ";
                    for (int i = 0; i < _BattleBoxes[newP.BoxNum].WaitQ.Count; i++)
                    {
                        wait_list += " [" + (i + 1) + "]" + _BattleBoxes[newP.BoxNum].WaitQ[i] + ",";
                    }

                    q.Enqueue(msg.pm(player.PlayerName, wait_list));
                }
            }
        }
        public void InStartBox(Battle.StatusControl.MainPlayer Splayer, Queue<EventArgs> q)
        {
            BattlePlayer Bplayer = _BattlePlayers.Find(item => item.PlayerName == Splayer.PlayerName);

            if (Bplayer != null)
            {
                if (Bplayer.Freq != Splayer.Freq)
                    q.Enqueue(msg.pm(Bplayer.PlayerName, "*setfreq " + Bplayer.Freq));
                else
                {
                    Random ran = new Random();
                    Splayer.WarpStamp = DateTime.Now;
                    q.Enqueue(msg.warp(Bplayer.PlayerName, ran.Next(_BattleBoxes[Bplayer.BoxNum].Location[0], _BattleBoxes[Bplayer.BoxNum].Location[2]), ran.Next(_BattleBoxes[Bplayer.BoxNum].Location[1], _BattleBoxes[Bplayer.BoxNum].Location[3])));

                }
            }
        }
    }
}
